/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_interval_optimizer.cpp                                               *
 ****************************************************************************/

#include "elisa_interval_optimizer.h"


USING_ELISA

//--------------------------------------------------------------------------
// class IntervalOptimizer
//--------------------------------------------------------------------------
bool IntervalOptimizer::end()
{
	if (_sol.size() == 0) {
		return false;
	} else {
		// Evaluation of the objective over a computed box _sol[i]
		Interval I = _f->eval(_sol[_sol.size() - 1]);
		if (I.inf() > _min) {
			// Elimination of the box
			delete _sol[_sol.size() - 1];
			_sol.resize(_sol.size() - 1);
			return IntervalOptimizer::end();
		} else {
			// The solution becomes the current solution in the heap
			m_searchTree.getHeap()->addBox(_sol[_sol.size() - 1]);

			// Apply the solution handler
			m_searchOutput->handle(++m_numSol);

			// Elimination of the box in the vector
			delete _sol[_sol.size() - 1];
			_sol.resize(_sol.size() - 1);

			// Reliable bound of the minimum
			_minimum = I;
			m_model->updateSymbolicDomain();

			return true;
		}
	}
}

bool IntervalOptimizer::next()
{
	if (m_numDom > 0) {
		return IntervalOptimizer::end();
	}

	// ELSE Computation of ALL global optima
	Solver::reset();
	_min = Interval::Universe.sup();

	// Loop until a solution box is computed
	while (!m_searchTree.isEmpty()) {
		++m_numDom;

		// Reduction
		if (reduce()) {
			// Evaluation of the objective over the current box
			Interval I = _f->eval();
			// Does I not contain a global minimum?
			if (I.inf() > _min) {
				(*m_backTrack)();
			} else {
				// Has a new bound been computed?
				if ((I.sup() < _min) && _prover->exists()) {
					// ONLY IF EXISTENCE PROOF OF SOLUTION IN THE CURRENT BOX
					_min = I.sup();
				}
				// Is the box precise enough?
				if (this->isSolution()) {
					// Extraction from the heap to the vector _sol
					_sol.push_back(m_searchTree.copyBox());
					(*m_backTrack)();
					// Case of INNER approximation => non-constrained optimization
				} else {
					// Reduction ok, but the box is not a solution => splitting
#ifdef ELISA_PROFILE
					++m_numSplit;
#endif

					// Compute the next variable to split
					(*m_makeNeighborhood)();
					(*m_move)();
				}
			}
		} else {
			// Reduction => inconsistency
			(*m_backTrack)();
		}
	}
	return IntervalOptimizer::end();
}
